package com.hjk.common.utils.lambda;


import cn.hutool.core.lang.copier.Copier;
import com.hjk.common.utils.check.Check;
import com.hjk.common.utils.concurrency.FastTaskUtils;
import com.hjk.common.utils.math.ArithUtlis;
import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang3.ObjectUtils;
import org.junit.Test;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 流式编程工具类
 *
 * @author huangjunkai
 * @version 1.0
 * @date 2020/01/12 15:13
 */
@Slf4j
public class Streams {

    /**
     * 函数式接口
     *
     * @param function  轮回者 {@link java.util.function.Function function}
     * @param predicate 判断者 {@link java.util.function.Predicate predicate}
     * @param consumer  消费者 {@link java.util.function.Consumer consumer}
     * @param supplier  提供者 {@link java.util.function.Supplier supplier}
     * @param <T>
     * @param <R>
     */
    public <T, R> void functionInterface(Function<T, R> function, Predicate<T> predicate, Consumer<R> consumer, Supplier<T> supplier) {
        if (predicate.test(supplier.get())) {
            R apply = function.apply(supplier.get());
            consumer.accept(apply);
        }
    }

    /**
     * 建议list数据在十万级,百万级以上使用
     * 并发流:收集list的元素 tolist
     */
    public static <T, V> List<V> parallelToList(List<T> list, Function<? super T, ? extends V> mapper) {
        if (ObjectUtils.isEmpty(list)) {
            return null;
        }
        return list.parallelStream().map(mapper).filter(ObjectUtils::isNotEmpty).collect(Collectors.toList());
    }

    /**
     * list在十万级以下使用
     * 普通流:收集list的元素 tolist
     */
    public static <T, R> List<R> toList(Collection<T> list, Function<? super T, ? extends R> mapper) {
        if (ObjectUtils.isEmpty(list)) {
            return null;
        }
        return list.stream().map(mapper).filter(ObjectUtils::isNotEmpty).collect(Collectors.toList());
    }

    public static <T> String join(List<T> list, Function<T, String> mapper, CharSequence delimiter) {
        if (ObjectUtils.isEmpty(list)) {
            return null;
        }
        return list.stream().filter(ObjectUtils::isNotEmpty).map(mapper).collect(Collectors.joining(delimiter));
    }

    /**
     * list在十万级以下使用
     * 普通流:收集list的元素 toSet
     */
    public static <T, V> Set<V> toSet(Collection<T> list, Function<? super T, ? extends V> mapper) {
        if (ObjectUtils.isEmpty(list)) {
            return null;
        }
        return list.stream().map(mapper).filter(ObjectUtils::isNotEmpty).collect(Collectors.toSet());
    }

    /**
     * list在十万级以下使用
     * 普通流:过滤list集合后收集元素 tolist
     */
    public static <T> List<T> filterToList(Collection<T> list, Predicate<T> predicate) {
        if (ObjectUtils.isEmpty(list)) {
            return null;
        }
        return list.stream().filter(predicate).collect(Collectors.toList());
    }

    /**
     * list在十万级以下使用
     * 普通流:先收集元素,后过滤   tolist
     */
    public static <T, V> List<? extends V> mapFilterToList(Collection<T> list, Function<? super T, ? extends V> mapper, Predicate<V> predicate) {
        if (ObjectUtils.isEmpty(list)) {
            return null;
        }
        return list.stream().map(mapper).filter(predicate).collect(Collectors.toList());
    }

    /**
     * list在十万级以下使用
     * 普通流: 扁平化处理收集元素   tolist
     */
    public static <T, V> List<V> flatToList(Collection<T> list, Function<? super T, ? extends Stream<? extends V>> mapper) {
        if (ObjectUtils.isEmpty(list)) {
            return null;
        }
        return list.stream().flatMap(mapper).filter(ObjectUtils::isNotEmpty).collect(Collectors.toList());
    }
    /**
     * List 转 Map 如果有重复的Key会报错：java.lang.IllegalStateException: Duplicate key
     * 正确写法（去重）： Collectors.toMap(mapper, Function.identity(), (dto1, dto2) -> dto1)
     */
    public static <T, V> Map<V, T> toMap(Collection<T> list, Function<T, V> mapper) {
        if (ObjectUtils.isEmpty(list)) {
            return null;
        }
        return list.stream().collect(Collectors.toMap(mapper, Function.identity(), (dto1, dto2) -> dto1));
    }

    /**
     * List 转 Map
     *
     * @param list        集合
     * @param keyMapper   集合某个属性
     * @param valueMapper 集合某个属性
     * @return map<集合某个属性, 集合某个属性>
     */
    public static <T, V, U> Map<V, U> toMap(Collection<T> list, Function<T, V> keyMapper, Function<T, U> valueMapper) {
        if (ObjectUtils.isEmpty(list)) {
            return null;
        }
        return list.stream().collect(Collectors.toMap(keyMapper, valueMapper));
    }

    /**
     * list在十万级以下使用
     * 普通流: 根据mapper条件groupingBy成Map<V, List<T>
     */
    public static <T, V> Map<V, List<T>> groupingBy(List<T> list, Function<T, V> mapper) {
        if (ObjectUtils.isEmpty(list)) {
            return null;
        }
        return list.stream().collect(Collectors.groupingBy(mapper));
    }

    public static <T> BigDecimal exchandgeRMP(Map<Integer, List<T>> currencySort, Function<T, BigDecimal> mapper, HashMap<Integer, BigDecimal> currencyMap) {
        BigDecimal totalAmount = BigDecimal.ZERO;
        for (Map.Entry<Integer, List<T>> entry : currencySort.entrySet()) {
            BigDecimal currencyPrice = entry.getValue().stream()
                    .map(mapper)
                    .reduce(BigDecimal.ZERO, BigDecimal::add)
                    .multiply(currencyMap.get(entry.getKey()));
            totalAmount = totalAmount.add(currencyPrice);
        }
        return totalAmount;
    }


    /**
     * 集合 转换成 map  或者  null
     *
     * @param list   [{id:1,name:a},{id:2,name:b},{id:3,name:c}]
     * @param mapper id
     * @return {1 :{id:1,name:a},2:{id:2,name:b},3:{id:3,name:c}}
     */
    public static <T, V> Map<V, T> toMapOfNull(List<T> list, Function<T, V> mapper) {
        return ObjectUtils.isNotEmpty(list) ? Streams.toMap(list, mapper) : null;
    }

    /**
     * 返回boolean值,如果predicate 都为true,返回true,存在false则返回false
     *
     * @param <T>
     * @param list
     * @param mapper
     * @return
     */
    public static <T> Boolean every(List<T> list, Function<T, Boolean> mapper) {
        if (ObjectUtils.isEmpty(list)) {
            return null;
        }
        for (Boolean aBoolean : list.stream().map(mapper).collect(Collectors.toList())) {
            if (!aBoolean) {
                return false;
            }
        }
        return true;
    }


    /**
     * 计算集合元素
     *
     * @param list   集合
     * @param mapper 集合中某个属性
     * @param op     计算规则
     */
    public static <T> double reduceBy(List<T> list, ToDoubleFunction<T> mapper, DoubleBinaryOperator op) {
        if (ObjectUtils.isEmpty(list)) {
            return 0.0;
        }
        return list.stream().mapToDouble(mapper).reduce(op).orElse(0.0);
    }

    /**
     * 计算集合元素
     *
     * @param list   集合
     * @param mapper 集合中某个属性
     * @param op     计算规则
     */
    public static <T, R> BigDecimal reduceBy(List<T> list, Function<T, BigDecimal> mapper, BinaryOperator<BigDecimal> op) {
        if (ObjectUtils.isEmpty(list)) {
            return BigDecimal.ZERO;
        }
        return list.stream().filter(ObjectUtils::isNotEmpty).map(mapper).reduce(op).orElse(BigDecimal.ZERO);
    }

    /**
     * 累加集合元素
     *
     * @param list   集合
     * @param mapper 集合中某个属性
     * @param op     计算规则
     */
    public static <T> double reduceByAdd(List<T> list, ToDoubleFunction<T> mapper, DoubleBinaryOperator op) {
        if (ObjectUtils.isEmpty(list)) {
            return 0.0;
        }
        return list.stream().mapToDouble(mapper).reduce(ArithUtlis::add).orElse(0.0);
    }

    public static <U> Supplier<U> trySupplier(Supplier<U> supplier) {
        return () -> {
            try {
                return supplier.get();
            } catch (Exception e) {
                log.error("调用 [  ] 失败 :" + e.getMessage(), e);
            }
            return null;
        };
    }

    public static void main(String[] args) {
        trySupplier(() -> 1 / 0);
    }


}
